package com.os.utils;

import com.os.content.MemoryContent;
import com.os.pojo.PCB;
import com.os.pojo.virtualmemory.Page;
import com.os.pojo.virtualmemory.Segment;
import com.os.pojo.vo.AddressVo;

import java.util.LinkedList;
import java.util.List;

/**
 * 一些算法实现类
 */
public class AlgorithmUtils {

    /**
     * 将size转换为内存块的整数倍
     */
    public static int countMemorySize(int size) {
        // 获取内存块大小
        int frameSize = MemoryContent.FRAME_SIZE;
        if (size % frameSize == 0) return size;
        return size + (frameSize - size % frameSize);
    }


    public static int getBinaryLen(int x) {
        return Integer.toBinaryString(x).length();
    }

    public static int createMask(int bits) {
        return (1 << bits) - 1;
    }

    /**
     * 将字符转成字符串
     */
    public static String getChat(char c, boolean isEscape) {
        if (!isEscape) return c + "";
        if (c == 0) return "-";
        else if (c == '\n') return "\\n";
        return c + "";
    }

    /**
     * 字符数组转字符串，isEscape为是否转义
     */
    public static String getPageChats(char[] chars, boolean isEscape) {
        if (chars == null) chars = new char[MemoryContent.FRAME_SIZE];
        StringBuilder ss = new StringBuilder();
        for (char c : chars) {
            String s = getChat(c, isEscape);
            ss.append(s);
        }
        String string = ss.toString();
        return string;
    }

    /**
     * 将段号，页号，偏移量合并成一个逻辑地址
     */
    public static int idToAddress(int segmentId, int pageId, int offset) {
        // 求偏移量的位
        int offsetBit = AlgorithmUtils.getBinaryLen(MemoryContent.FRAME_SIZE - 1);

        // 页号位
        int PageIdBit = AlgorithmUtils.getBinaryLen(MemoryContent.PAGE_MAX_NUMBER - 1);

        // 通过位运算将segmentId, pageId, offset合并为一个整数
        int logicAddress = (segmentId << (PageIdBit + offsetBit)) | (pageId << offsetBit) | offset;

        return logicAddress;
    }

    /**
     * 计算物理地址
     * @param frameId
     * @param offset
     * @return
     */
    public static int idToPhyscialAddress(int frameId, int offset) {
        // 求偏移量的位
        int offsetBit = AlgorithmUtils.getBinaryLen(MemoryContent.FRAME_SIZE - 1);

        return (frameId << offsetBit) | offset;

    }

    /**
     * 将逻辑地址分割
     */
    public static AddressVo splitAddress(int address) {
        // 求偏移量的位
        int offsetBit = AlgorithmUtils.getBinaryLen(MemoryContent.FRAME_SIZE - 1);
        // 页号位
        int PageIdBit = AlgorithmUtils.getBinaryLen(MemoryContent.PAGE_MAX_NUMBER - 1);

        int offset = address & AlgorithmUtils.createMask(offsetBit);

        int segmentId = (address >> (offsetBit + PageIdBit));

        int pageId = (address >> offsetBit) & AlgorithmUtils.createMask(PageIdBit);
        return new AddressVo(segmentId, pageId, offset);
    }

    /**
     * 获取区间内的整数列表，左闭右开
     *
     * @param start
     * @param end
     * @return
     */
    public static void getRange(List<Integer> list, int start, int end) {
        for (int i = start; i < end; i++) {
            list.add(i);
        }

    }


    public static void checkAddress(PCB pcb, AddressVo addressVo) {
        // 越界
        if (addressVo.getSegmentId() >= pcb.segmentTable.segments.length) {
            throw new ArrayIndexOutOfBoundsException("段号超出范围");
        } else if (addressVo.getPageId() >= pcb.segmentTable.segments[addressVo.getSegmentId()].pageTable.pages.length) {
            throw new ArrayIndexOutOfBoundsException("页号超出范围");
        } else if (addressVo.getOffset() >= pcb.segmentTable.segments[addressVo.getSegmentId()].pageTable.pages[addressVo.getPageId()].len) {
            throw new ArrayIndexOutOfBoundsException("偏移量超出范围");
        }

    }

}
